/*
 * Copyright 2002-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using Spring.Objects.Factory.Config;

namespace Spring.Objects.Factory;

/// <summary>
/// Simple factory to allow testing of IFactoryObject support in AbstractObjectFactory.
/// Depending on whether its singleton property is set, it will return a singleton
/// or a prototype instance.
/// Implements the IInitializingObject interface, so we can check that factories get
/// this lifecycle callback if they want.
/// </summary>
/// <author>Rod Johnson</author>
/// <author>Rick Evans (.NET)</author>
public class DummyFactory :
    IFactoryObject,
    IObjectFactoryAware,
    IObjectNameAware,
    IInitializingObject,
    IDisposable
{
    public const string SINGLETON_NAME = "Factory singleton";

    /// <summary>
    /// Creates a new instance of the
    /// <see cref="Spring.Objects.Factory.DummyFactory"/> class.
    /// </summary>
    public DummyFactory()
    {
        testObject = new TestObject();
        testObject.Name = SINGLETON_NAME;
        testObject.Age = 25;
    }

    /// <summary>
    /// Was this initialized by invocation of the
    /// AfterPropertiesSet() method from the IInitializingObject interface?
    /// </summary>
    public virtual bool WasInitialized
    {
        get { return initialized; }
    }

    public static bool WasPrototypeCreated
    {
        get { return prototypeCreated; }
    }

    public virtual bool PostProcessed
    {
        get { return postProcessed; }

        set { postProcessed = value; }
    }

    public virtual ITestObject OtherTestObject
    {
        get { return otherTestObject; }

        set { otherTestObject = value; }
    }

    /// <summary>
    /// Clear static state.
    /// </summary>
    public static void Reset()
    {
        prototypeCreated = false;
    }

    /// <summary> Default is for factories to return a singleton instance.</summary>
    private bool singleton = true;

    private String objectName;
    private IAutowireCapableObjectFactory objectFactory;
    private bool postProcessed;
    private bool initialized;
    private static bool prototypeCreated;
    private TestObject testObject;
    private ITestObject otherTestObject;

    public Type ObjectType
    {
        get
        {
//				if (!initialized)
//				{
//					throw new InvalidOperationException("'ObjectType' must not be called before AfterPropertiesSet()");
//				}
            return testObject.GetType();
        }
    }

    public object GetObject()
    {
//			if (!initialized)
//			{
//				throw new InvalidOperationException("GetObject() must not be called before AfterPropertiesSet()");
//			}

        if (IsSingleton)
        {
            return testObject;
        }
        else
        {
            TestObject prototype = new TestObject("Prototype created at " + DateTime.Now.Millisecond, 11);
            if (objectFactory != null)
            {
                objectFactory.ApplyObjectPostProcessorsBeforeInitialization(prototype, objectName);
            }

            prototypeCreated = true;
            return prototype;
        }
    }

    public bool IsSingleton
    {
        get { return singleton; }
        set { singleton = value; }
    }

    public IObjectFactory ObjectFactory
    {
        get { return objectFactory; }
        set
        {
            objectFactory = (IAutowireCapableObjectFactory) value;
            objectFactory.ApplyObjectPostProcessorsBeforeInitialization(testObject, objectName);
        }
    }

    public string ObjectName
    {
        get { return objectName; }
        set { objectName = value; }
    }

    public void AfterPropertiesSet()
    {
        if (initialized)
        {
            throw new SystemException(
                "Cannot call AfterPropertiesSet twice on the one object.");
        }

        initialized = true;
    }

    public void Dispose()
    {
        if (testObject != null)
        {
            testObject.Name = null;
        }
    }
}
